//
// Created by 罗俊华 on 2022/1/13.
//
#include <iostream>

using namespace std;

void pointer_basic();

void storageAllocation();

void createArrayByNew();
void array_address();
int main() {

//    pointer_basic();
//    storageAllocation();
//    createArrayByNew();
    array_address();
    return 0;
}

// 指针的基本使用
void pointer_basic() {

    int a = 100;
//    指针尚未被初始化，可能有任何值
//    int *p_a; //强调： *p_a 是一个 int 类型的值
//    int * p_a;
    int *p_a; // 强调：int* 是一种类型：指向 int的指针

//    将指针 p_a 的值设置为 a 变量的地址
    p_a = &a;

    cout << "a = " << a << "其地址是：" << p_a << endl;
//  p84：在对指针解除引用（*p_a）之前，必须将指针初始化为一个确定的、适当的地址
//      这是关于使用指针的金科玉律
    *p_a = *p_a + 10;

    cout << "a = " << a << "其地址是：" << p_a << endl;

//    cout << "指针是a吗？" << a == *p_a;
}

// 在运行阶段使用 new 关键字 为 int 值分配未命名的内存，并使用指针来访问这个值
void storageAllocation() {

//    new 将找到一个长度适合的内存块，并返回该内存块的地址
//    new 运算符根据类型来确定需要多少字节的内存，然后找到这样的内存，并返回其地址
//    这种情况下，只能通过指针来访问刚分配的内存
    int *p_int = new int;

    cout << "为 int 分配到的内存是：" << p_int << "，此地址未初始化时，上面存储的值是：" << *p_int << endl;

    *p_int = 99;

    cout << "为指针赋值之后为：" << *p_int << "，地址为" << p_int << endl;

//    只能释放 new 分配的内存（只能释放一次
//    但是 p_int 指针本身不会被删除
//    对空指针使用 delete 是安全的
    delete p_int;
}

// 使用 new 关键字来在堆中动态创建数组
void createArrayByNew() {

    const int array_size = 10;
/*
 * 数组名（arr）将指向包含 10 个 int 值的内存块中的第一个元素
 * 假设 int 占用 4个字节，结合数组长度就能知道整个数组占用的所有字节数
 * */
    int *arr = new int[array_size];

//    其中 数组名 指向数组中的第一个元素
    int a = 0;

//    使用指针来遍历数组
    for (int *i = arr; i < arr + array_size; ++i) {

        *i = a;
        a++;
    }
//   使用下表索引来遍历数组
//      注意：不能使用 sizeof 来确定动态分配（使用new关键字）的数组包含的字节数
    for (int i = 0; i < array_size; ++i) {
        cout << "数组中的第" << i << "个元素用 arr[i]取出是：" << arr[i] << "，使用 *(arr +i)取出是：" << *(arr + i) << "，其地址为：" << &arr[i]
             << endl;
/*        arr[i] 最终会被解释为 *(arr+i)，两者是等价的
 *      *(arr + i) 将指针变量加i了之后，增加的量等于 指针指向类型所占用的字节数（sizeof int）* i
 */
    }

    cout << "错误：使用 sizeof 查看 new 创建出的数组的长度：" << sizeof arr << endl;

    int* p_arr = arr;
/*    对指向数组的指针使用 sizeof 能得到指针的长度
 *    对数组名使用 sizeof 得到的是数组的长度，
 *    这也是为什么 new 关键字创建出来的数组不能使用 sizeof 的原因
 *    因为 new 关键字创建出来的数组，返回的是一个指向该内存的指针，而不是数组名
 *    对指向数组的指针使用 sizeof 得到的是 该指针的长度
 */
    cout << "对数组名使用sizeof：" << sizeof arr<<"，对指向数组的指针使用 sizeof ："<< sizeof p_arr<<endl;

//    释放数组占用内存
    delete[] arr;
}

// 数组的地址
void array_address(){

    short arr[10];

    cout << "数组第一个元素的地址是：" << arr <<"，将其 + 1 之后为："<< arr+1<<endl;
//  对数组中第一个元素的地址+1，相当于加了 (sizeof short) -> 2 字节

//    数组的地址
    short (*p)[10] = &arr;


/*    对数组的地址 +1，相当于加了(sizeof arr) -> 20 字节
 *    通过sizeof 运算符可以看出，此方式只能适用于 非new关键字创建出来的数组
 *    因为对new关键字创建出来的数组，sizeof 数组名 得到的长度是 指针的长度
 */
    cout << "数组的地址："<<p<<"，将其 + 1 之后为："<< p+1<<endl;

//    delete[] arr;
}
